(() => {
  // ------------------1. 函数定义------------------
  // 定义普通函数
  function add(x: number, y: number): number {
    return x + y
  }
  console.log(add(2, 3)) // 5
  // 定义匿名函数（函数表达式）：函数赋值给变量
  let myAdd2 = function (x: number, y: number): number {
    return x + y
  }
  console.log(myAdd2(2, 3)) // 5
  // 定义匿名函数（箭头函数）：箭头函数赋值给变量
  let myAdd3 = (x: number, y: number): number => {
    return x + y
  }
  console.log(myAdd2(2, 3)) // 5
  // 书写完整函数类型
  let myAdd4: (baseValue: number, increment: number) => number = function (x: number, y: number): number {
    return x + y
  }
  // type别名
  type myAddType = (baseValue: number, increment: number) => number
  let myAdd5: myAddType = function (x: number, y: number): number {
    return x + y
  }
  // ------------------2. 函数的可选参数？------------------
  /**
   * 函数的可选参数：
   * 1. 可选参数必须放在必选参数后面
   * 2. 可选参数的类型声明带上undefined，严谨书写
   * 3. 返回值处必须处理可选值，用逻辑中断表示可能值
   */
  const fn = (name: string, age?: number | undefined): string => {
    return name + (age || '未知')
  }
  let str1 = fn('zhangsan')
  console.log(str1);

  // ------------------3. 函数的默认参数------------------
  /**
   * 函数的默认参数 VS 可选参数：
   * 1. 默认参数：函数调用时，如果没有传入该参数，则使用默认值
   * 2. 可选参数：函数调用时，如果没有传入该参数，则不传
   * 3. 选择默认参数可以不用处理可选参数
   * 4. 默认参数的可读性更强，const fn1: (name?: string) => string
   */
  const fn1 = (name: string = '我是默认值'): string => {
    return name
  }
  fn1() // 我是默认值
  // ------------------4. 定义剩余参数------------------
  const fn2 = (array: number[], ...items:number[] ): any[] => {
    console.log(array, items);
    return items
  }
  let b: number[] = [1, 2, 3, 6]
  let result = fn2(b, 1, 2, 3, 4, 5)
  console.log(result);  // [1, 2, 3, 4, 5]

  // ------------------5. 接口定义函数------------------
  interface IAdd {
    (num: number, num2: number): number
  }

  const fn3: IAdd = (num: number, num2: number): number => {
    return num + num2
  }
  fn3(2, 3) // 5

  interface User {
    name: string
    age: number
  }
  function getUserInfo(user: User): User {
    return user
  }
})()
